From bd495a7716bdb8cc8f46effc6a5e6418861c1015 Mon Sep 17 00:00:00 2001 From: "iap10@labyrinth.cl.cam.ac.uk" Date: Sat, 12 Jul 2003 18:42:51 +0000 Subject: [PATCH] bitkeeper revision 1.340 (3f1056abln89ZkMr4cSW4WAtN8rLsg) VGA console support for domain0. put the following on the kernel command line: console=xencons0 console=tty0 --- .rootkeys | 2 + xen/common/domain.c | 10 +- xen/common/memory.c | 2 +- xen/include/xeno/console.h | 3 +- .../arch/xeno/kernel/ioport.c | 29 +- .../arch/xeno/kernel/setup.c | 2 + xenolinux-2.4.21-sparse/arch/xeno/mm/init.c | 5 +- .../arch/xeno/mm/ioremap.c | 48 ++ .../include/asm-xeno/fixmap.h | 6 +- .../include/asm-xeno/vga.h | 57 ++ xenolinux-2.4.21-sparse/kernel/printk.c | 691 ++++++++++++++++++ xenolinux-2.4.21-sparse/mkbuildtree | 1 - 12 files changed, 845 insertions(+), 11 deletions(-) create mode 100644 xenolinux-2.4.21-sparse/include/asm-xeno/vga.h create mode 100644 xenolinux-2.4.21-sparse/kernel/printk.c diff --git a/.rootkeys b/.rootkeys index 037fbbc3f8..7adf19e064 100644 --- a/.rootkeys +++ b/.rootkeys @@ -583,11 +583,13 @@ 3e5a4e68uJz-xI0IBVMD7xRLQKJDFg xenolinux-2.4.21-sparse/include/asm-xeno/segment.h 3e5a4e68Nfdh6QcOKUTGCaYkf2LmYA xenolinux-2.4.21-sparse/include/asm-xeno/smp.h 3e5a4e68mTr0zcp9SXDbnd-XLrrfxw xenolinux-2.4.21-sparse/include/asm-xeno/system.h +3f1056a9L_kqHcFheV00KbKBzv9j5w xenolinux-2.4.21-sparse/include/asm-xeno/vga.h 3f056927gMHl7mWB89rb73JahbhQIA xenolinux-2.4.21-sparse/include/linux/blk.h 3e5a4e68WLX3B8owTvktP3HHOtznPQ xenolinux-2.4.21-sparse/include/linux/major.h 3e5a4e686V0nioX2ZpFf056sgvdiQw xenolinux-2.4.21-sparse/include/linux/sunrpc/debug.h 3e5a4e68W_hpMlM3u_-QOKMp3gzcwQ xenolinux-2.4.21-sparse/init/do_mounts.c 3e5a4e68TJJavrunYwTAnLRSBxSYqQ xenolinux-2.4.21-sparse/kernel/panic.c +3f1056a9LXNTgSzITNh1mb-MIKV1Ng xenolinux-2.4.21-sparse/kernel/printk.c 3eba8f878XjouY21EkQBXwYBsPsipQ xenolinux-2.4.21-sparse/lndir-rel 3e6e7c1efbQe93xCvOpOVCnXTMmQ5w xenolinux-2.4.21-sparse/mkbuildtree 3e5a4e68GxCIaFH4sy01v1wjapetaA xenolinux-2.4.21-sparse/mm/memory.c diff --git a/xen/common/domain.c b/xen/common/domain.c index 06e67e7dc5..34d98d7d07 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -677,7 +677,7 @@ int setup_guestos(struct task_struct *p, dom0_newdomain_t *params, // 1) its privileged (need iopl right now) // 2) its the owner of the console (and therefore will get kbd/mouse events) // 3) xen hasnt tried to touch the console (see console.h) - virt_startinfo_address->flags |= (IS_PRIV(p) && CONSOLE_ISOWNER(p) && opt_console == 0) ? SIF_CONSOLE : 0; + virt_startinfo_address->flags |= (IS_PRIV(p) && CONSOLE_ISOWNER(p) ) ? SIF_CONSOLE : 0; if ( initrd_len ) { @@ -718,6 +718,14 @@ int setup_guestos(struct task_struct *p, dom0_newdomain_t *params, } *dst = '\0'; + /* If this guy's getting the console we'd better let go */ + if ( virt_startinfo_address->flags & SIF_CONSOLE ) + { + // should reset the console, but seems to work anyhow... + opt_console = 0; + } + + /* Reinstate the caller's page tables. */ __write_cr3_counted(pagetable_val(current->mm.pagetable)); __sti(); diff --git a/xen/common/memory.c b/xen/common/memory.c index 637112d241..ab26b664d8 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -184,7 +184,7 @@ /* Domain 0 is allowed to submit requests on behalf of others. */ #define DOMAIN_OKAY(_f) \ - ((((_f) & PG_domain_mask) == current->domain) || (current->domain == 0)) + (((_f) & PG_domain_mask) == current->domain) /* 'get' checks parameter for validity before inc'ing refcnt. */ static int get_l2_table(unsigned long page_nr); diff --git a/xen/include/xeno/console.h b/xen/include/xeno/console.h index 3208b1e3a9..75fb3f5074 100644 --- a/xen/include/xeno/console.h +++ b/xen/include/xeno/console.h @@ -26,7 +26,8 @@ // the notion of privileges for guest os's (e.g. console privilege) has not been explored yet // so this will do for now -#define CONFIG_OUTPUT_CONSOLE 1 // but see also opt_console +#define CONFIG_OUTPUT_CONSOLE 1 // XXX You need to undef this + // but see also opt_console #define CONFIG_OUTPUT_SERIAL 1 extern unsigned int opt_console; diff --git a/xenolinux-2.4.21-sparse/arch/xeno/kernel/ioport.c b/xenolinux-2.4.21-sparse/arch/xeno/kernel/ioport.c index c946fc4d37..2dd89e4a11 100644 --- a/xenolinux-2.4.21-sparse/arch/xeno/kernel/ioport.c +++ b/xenolinux-2.4.21-sparse/arch/xeno/kernel/ioport.c @@ -8,8 +8,33 @@ asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on) { - /* No IO permission! Selective IO perms aren't virtualised yet. */ - return -EPERM; + unsigned int new_io_pl = (turn_on)?3:0; + unsigned int old_io_pl = current->thread.io_pl; + dom0_op_t op; + + if ( !(start_info.flags & SIF_PRIVILEGED) ) + return -EPERM; + + /* Need "raw I/O" privileges for direct port access. */ + if ( (new_io_pl > old_io_pl) && !capable(CAP_SYS_RAWIO) ) + return -EPERM; + + /* Maintain OS privileges even if user attempts to relinquish them. */ + if ( (new_io_pl == 0) && (start_info.flags & SIF_PRIVILEGED) ) + new_io_pl = 1; + + printk("ioperm not properly supported - set iopl to %d\n",new_io_pl); + + /* Change our version of the privilege levels. */ + current->thread.io_pl = new_io_pl; + + /* Force the change at ring 0. */ + op.cmd = DOM0_IOPL; + op.u.iopl.domain = start_info.dom_id; + op.u.iopl.iopl = new_io_pl; + HYPERVISOR_dom0_op(&op); + + return 0; } diff --git a/xenolinux-2.4.21-sparse/arch/xeno/kernel/setup.c b/xenolinux-2.4.21-sparse/arch/xeno/kernel/setup.c index 80f55c6cb6..51dbe125b0 100644 --- a/xenolinux-2.4.21-sparse/arch/xeno/kernel/setup.c +++ b/xenolinux-2.4.21-sparse/arch/xeno/kernel/setup.c @@ -58,6 +58,8 @@ struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; unsigned long mmu_cr4_features; +unsigned char * vgacon_mmap; + /* * Bus types .. */ diff --git a/xenolinux-2.4.21-sparse/arch/xeno/mm/init.c b/xenolinux-2.4.21-sparse/arch/xeno/mm/init.c index 462e51c501..acce1fbfd7 100644 --- a/xenolinux-2.4.21-sparse/arch/xeno/mm/init.c +++ b/xenolinux-2.4.21-sparse/arch/xeno/mm/init.c @@ -113,10 +113,7 @@ static inline void set_pte_phys (unsigned long vaddr, return; } pte = pte_offset(pmd, vaddr); -#if 0 // XXX Xen ????? - /* stored as-is, to permit clearing entries */ - set_pte(pte, mk_pte_phys(phys, flags)); -#endif + if (pte_val(*pte)) pte_ERROR(*pte); diff --git a/xenolinux-2.4.21-sparse/arch/xeno/mm/ioremap.c b/xenolinux-2.4.21-sparse/arch/xeno/mm/ioremap.c index f7c6fad278..b15b8fc3cb 100644 --- a/xenolinux-2.4.21-sparse/arch/xeno/mm/ioremap.c +++ b/xenolinux-2.4.21-sparse/arch/xeno/mm/ioremap.c @@ -296,6 +296,54 @@ void iounmap(void *addr) printk(KERN_ERR "Trying to iounmap() nonexistent vm area (%p)\n", addr); } +void __init *bt_ioremap(unsigned long machine_addr, unsigned long size) +{ + unsigned long offset, last_addr; + unsigned int nrpages; + enum fixed_addresses idx; + + /* Don't allow wraparound or zero size */ + last_addr = machine_addr + size - 1; + if (!size || last_addr < machine_addr) + return NULL; + + /* + * Mappings have to be page-aligned + */ + offset = machine_addr & ~PAGE_MASK; + machine_addr &= PAGE_MASK; + size = PAGE_ALIGN(last_addr) - machine_addr; + + /* + * Mappings have to fit in the FIX_BTMAP area. + */ + nrpages = size >> PAGE_SHIFT; + if (nrpages > NR_FIX_BTMAPS) + return NULL; + + /* + * Ok, go for it.. + */ + idx = FIX_BTMAP_BEGIN; + while (nrpages > 0) { + set_fixmap(idx, machine_addr); + + //unsigned long address = __fix_to_virt(idx); + + + +//direct_set_pte(address, direct_mk_pte_phys(machine_addr, PAGE_KERNEL_NOCACHE)); + + machine_addr += PAGE_SIZE; + --idx; + --nrpages; + } + +flush_tlb_all(); + + return (void*) (offset + fix_to_virt(FIX_BTMAP_BEGIN)); +} + #if 0 /* We don't support these functions. They shouldn't be required. */ void __init *bt_ioremap(unsigned long machine_addr, unsigned long size) {} diff --git a/xenolinux-2.4.21-sparse/include/asm-xeno/fixmap.h b/xenolinux-2.4.21-sparse/include/asm-xeno/fixmap.h index eee16cb240..d6826ee365 100644 --- a/xenolinux-2.4.21-sparse/include/asm-xeno/fixmap.h +++ b/xenolinux-2.4.21-sparse/include/asm-xeno/fixmap.h @@ -47,8 +47,12 @@ enum fixed_addresses { FIX_NETRING1_BASE, FIX_NETRING2_BASE, FIX_NETRING3_BASE, +#define NR_FIX_BTMAPS 8 /* 32KB For the Dom0 VGA Console */ + FIX_BTMAP_END, + FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS - 1, + __end_of_permanent_fixed_addresses, - __end_of_fixed_addresses + __end_of_fixed_addresses = __end_of_permanent_fixed_addresses }; extern void __set_fixmap (enum fixed_addresses idx, diff --git a/xenolinux-2.4.21-sparse/include/asm-xeno/vga.h b/xenolinux-2.4.21-sparse/include/asm-xeno/vga.h new file mode 100644 index 0000000000..dc49a29529 --- /dev/null +++ b/xenolinux-2.4.21-sparse/include/asm-xeno/vga.h @@ -0,0 +1,57 @@ +/* + * Access to VGA videoram + * + * (c) 1998 Martin Mares + */ + +#ifndef _LINUX_ASM_VGA_H_ +#define _LINUX_ASM_VGA_H_ + +#include + +extern unsigned char *vgacon_mmap; + + +static unsigned long VGA_MAP_MEM(unsigned long x) +{ + + if( vgacon_mmap == NULL ) + { + /* This is our first time in this function. This whole thing + is a rather grim hack. We know we're going to get asked + to map a 32KB region between 0xb0000 and 0xb8000 because + that's what VGAs are. We used the boot time permanent + fixed map region, and map it to machine pages. + */ + + if( x != 0xb8000 ) + { + printk("Argghh! VGA Console is weird. 1:%08lx\n",x); + BUG(); + } + + vgacon_mmap = (unsigned char*) bt_ioremap( 0xb8000, 32*1024 ); +//xprintk("VGA_MAP_MEM(%08x) first. return %p\n",x,vgacon_mmap); + return (unsigned long) vgacon_mmap; + } + else + { + if( x != 0xc0000 ) + { + printk("Argghh! VGA Console is weird. 2:%08lx\n",x); + BUG(); + } +//xprintk("VGA_MAP_MEM(%08x) second. return %p\n",x,(unsigned long) vgacon_mmap+0x8000); + + return (unsigned long) vgacon_mmap + 0x8000; + + } + return 0; +} + +static inline unsigned char vga_readb(unsigned char * x) { +xprintk("vr %p\n",x);return (*(x)); } +static void vga_writeb(unsigned char x, unsigned char *y) { +xprintk("vw %02x %p\n",x,y); *(y) = (x); } + +#endif diff --git a/xenolinux-2.4.21-sparse/kernel/printk.c b/xenolinux-2.4.21-sparse/kernel/printk.c new file mode 100644 index 0000000000..46f16f35a8 --- /dev/null +++ b/xenolinux-2.4.21-sparse/kernel/printk.c @@ -0,0 +1,691 @@ +/* + * linux/kernel/printk.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Modified to make sys_syslog() more flexible: added commands to + * return the last 4k of kernel messages, regardless of whether + * they've been read or not. Added option to suppress kernel printk's + * to the console. Added hook for sending the console messages + * elsewhere, in preparation for a serial line console (someday). + * Ted Ts'o, 2/11/93. + * Modified for sysctl support, 1/8/97, Chris Horn. + * Fixed SMP synchronization, 08/08/99, Manfred Spraul + * manfreds@colorfullife.com + * Rewrote bits to get rid of console_lock + * 01Mar01 Andrew Morton + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For in_interrupt() */ +#include + +#include + +#if defined(CONFIG_MULTIQUAD) || defined(CONFIG_IA64) +#define LOG_BUF_LEN (65536) +#elif defined(CONFIG_ARCH_S390) +#define LOG_BUF_LEN (131072) +#elif defined(CONFIG_SMP) +#define LOG_BUF_LEN (32768) +#else +#define LOG_BUF_LEN (16384) /* This must be a power of two */ +#endif + +#define LOG_BUF_MASK (LOG_BUF_LEN-1) + +#ifndef arch_consoles_callable +#define arch_consoles_callable() (1) +#endif + +/* printk's without a loglevel use this.. */ +#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */ + +/* We show everything that is MORE important than this.. */ +#define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */ +#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */ + +DECLARE_WAIT_QUEUE_HEAD(log_wait); + +int console_printk[4] = { + DEFAULT_CONSOLE_LOGLEVEL, /* console_loglevel */ + DEFAULT_MESSAGE_LOGLEVEL, /* default_message_loglevel */ + MINIMUM_CONSOLE_LOGLEVEL, /* minimum_console_loglevel */ + DEFAULT_CONSOLE_LOGLEVEL, /* default_console_loglevel */ +}; + +int oops_in_progress; + +/* + * console_sem protects the console_drivers list, and also + * provides serialisation for access to the entire console + * driver system. + */ +static DECLARE_MUTEX(console_sem); +struct console *console_drivers; + +/* + * logbuf_lock protects log_buf, log_start, log_end, con_start and logged_chars + * It is also used in interesting ways to provide interlocking in + * release_console_sem(). + */ +static spinlock_t logbuf_lock = SPIN_LOCK_UNLOCKED; + +static char log_buf[LOG_BUF_LEN]; +#define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK]) + +/* + * The indices into log_buf are not constrained to LOG_BUF_LEN - they + * must be masked before subscripting + */ +static unsigned long log_start; /* Index into log_buf: next char to be read by syslog() */ +static unsigned long con_start; /* Index into log_buf: next char to be sent to consoles */ +static unsigned long log_end; /* Index into log_buf: most-recently-written-char + 1 */ +static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */ + +struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; +static int preferred_console = -1; + +/* Flag: console code may call schedule() */ +static int console_may_schedule; + +/* + * Setup a list of consoles. Called from init/main.c + */ +static int __init console_setup(char *str) +{ + struct console_cmdline *c; + char name[sizeof(c->name)]; + char *s, *options; + int i, idx; + + /* + * Decode str into name, index, options. + */ + if (str[0] >= '0' && str[0] <= '9') { + strcpy(name, "ttyS"); + strncpy(name + 4, str, sizeof(name) - 5); + } else + strncpy(name, str, sizeof(name) - 1); + name[sizeof(name) - 1] = 0; + if ((options = strchr(str, ',')) != NULL) + *(options++) = 0; +#ifdef __sparc__ + if (!strcmp(str, "ttya")) + strcpy(name, "ttyS0"); + if (!strcmp(str, "ttyb")) + strcpy(name, "ttyS1"); +#endif + for(s = name; *s; s++) + if (*s >= '0' && *s <= '9') + break; + idx = simple_strtoul(s, NULL, 10); + *s = 0; + + /* + * See if this tty is not yet registered, and + * if we have a slot free. + */ + for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) + if (strcmp(console_cmdline[i].name, name) == 0 && + console_cmdline[i].index == idx) { + preferred_console = i; + return 1; + } + if (i == MAX_CMDLINECONSOLES) + return 1; + preferred_console = i; + c = &console_cmdline[i]; + memcpy(c->name, name, sizeof(c->name)); + c->options = options; + c->index = idx; + return 1; +} + +__setup("console=", console_setup); + +/* + * Commands to do_syslog: + * + * 0 -- Close the log. Currently a NOP. + * 1 -- Open the log. Currently a NOP. + * 2 -- Read from the log. + * 3 -- Read all messages remaining in the ring buffer. + * 4 -- Read and clear all messages remaining in the ring buffer + * 5 -- Clear ring buffer. + * 6 -- Disable printk's to console + * 7 -- Enable printk's to console + * 8 -- Set level of messages printed to console + * 9 -- Return number of unread characters in the log buffer + */ +int do_syslog(int type, char * buf, int len) +{ + unsigned long i, j, limit, count; + int do_clear = 0; + char c; + int error = 0; + + switch (type) { + case 0: /* Close log */ + break; + case 1: /* Open log */ + break; + case 2: /* Read from log */ + error = -EINVAL; + if (!buf || len < 0) + goto out; + error = 0; + if (!len) + goto out; + error = verify_area(VERIFY_WRITE,buf,len); + if (error) + goto out; + error = wait_event_interruptible(log_wait, (log_start - log_end)); + if (error) + goto out; + i = 0; + spin_lock_irq(&logbuf_lock); + while ((log_start != log_end) && i < len) { + c = LOG_BUF(log_start); + log_start++; + spin_unlock_irq(&logbuf_lock); + __put_user(c,buf); + buf++; + i++; + spin_lock_irq(&logbuf_lock); + } + spin_unlock_irq(&logbuf_lock); + error = i; + break; + case 4: /* Read/clear last kernel messages */ + do_clear = 1; + /* FALL THRU */ + case 3: /* Read last kernel messages */ + error = -EINVAL; + if (!buf || len < 0) + goto out; + error = 0; + if (!len) + goto out; + error = verify_area(VERIFY_WRITE,buf,len); + if (error) + goto out; + count = len; + if (count > LOG_BUF_LEN) + count = LOG_BUF_LEN; + spin_lock_irq(&logbuf_lock); + if (count > logged_chars) + count = logged_chars; + if (do_clear) + logged_chars = 0; + limit = log_end; + /* + * __put_user() could sleep, and while we sleep + * printk() could overwrite the messages + * we try to copy to user space. Therefore + * the messages are copied in reverse. + */ + for(i=0;i < count;i++) { + j = limit-1-i; + if (j+LOG_BUF_LEN < log_end) + break; + c = LOG_BUF(j); + spin_unlock_irq(&logbuf_lock); + __put_user(c,&buf[count-1-i]); + spin_lock_irq(&logbuf_lock); + } + spin_unlock_irq(&logbuf_lock); + error = i; + if(i != count) { + int offset = count-error; + /* buffer overflow during copy, correct user buffer. */ + for(i=0;i 8) + goto out; + if (len < minimum_console_loglevel) + len = minimum_console_loglevel; + spin_lock_irq(&logbuf_lock); + console_loglevel = len; + spin_unlock_irq(&logbuf_lock); + error = 0; + break; + case 9: /* Number of chars in the log buffer */ + spin_lock_irq(&logbuf_lock); + error = log_end - log_start; + spin_unlock_irq(&logbuf_lock); + break; + default: + error = -EINVAL; + break; + } +out: + return error; +} + +asmlinkage long sys_syslog(int type, char * buf, int len) +{ + if ((type != 3) && !capable(CAP_SYS_ADMIN)) + return -EPERM; + return do_syslog(type, buf, len); +} + +/* + * Call the console drivers on a range of log_buf + */ +static void __call_console_drivers(unsigned long start, unsigned long end) +{ + struct console *con; + + for (con = console_drivers; con; con = con->next) { + if ((con->flags & CON_ENABLED) && con->write) + con->write(con, &LOG_BUF(start), end - start); + } +} + +/* + * Write out chars from start to end - 1 inclusive + */ +static void _call_console_drivers(unsigned long start, unsigned long end, int msg_log_level) +{ + if (msg_log_level < console_loglevel && console_drivers && start != end) { + if ((start & LOG_BUF_MASK) > (end & LOG_BUF_MASK)) { + /* wrapped write */ + __call_console_drivers(start & LOG_BUF_MASK, LOG_BUF_LEN); + __call_console_drivers(0, end & LOG_BUF_MASK); + } else { + __call_console_drivers(start, end); + } + } +} + +/* + * Call the console drivers, asking them to write out + * log_buf[start] to log_buf[end - 1]. + * The console_sem must be held. + */ +static void call_console_drivers(unsigned long start, unsigned long end) +{ + unsigned long cur_index, start_print; + static int msg_level = -1; + + if (((long)(start - end)) > 0) + BUG(); + + cur_index = start; + start_print = start; + while (cur_index != end) { + if ( msg_level < 0 && + ((end - cur_index) > 2) && + LOG_BUF(cur_index + 0) == '<' && + LOG_BUF(cur_index + 1) >= '0' && + LOG_BUF(cur_index + 1) <= '7' && + LOG_BUF(cur_index + 2) == '>') + { + msg_level = LOG_BUF(cur_index + 1) - '0'; + cur_index += 3; + start_print = cur_index; + } + while (cur_index != end) { + char c = LOG_BUF(cur_index); + cur_index++; + + if (c == '\n') { + if (msg_level < 0) { + /* + * printk() has already given us loglevel tags in + * the buffer. This code is here in case the + * log buffer has wrapped right round and scribbled + * on those tags + */ + msg_level = default_message_loglevel; + } + _call_console_drivers(start_print, cur_index, msg_level); + msg_level = -1; + start_print = cur_index; + break; + } + } + } + _call_console_drivers(start_print, end, msg_level); +} + +static void emit_log_char(char c) +{ + LOG_BUF(log_end) = c; + log_end++; + if (log_end - log_start > LOG_BUF_LEN) + log_start = log_end - LOG_BUF_LEN; + if (log_end - con_start > LOG_BUF_LEN) + con_start = log_end - LOG_BUF_LEN; + if (logged_chars < LOG_BUF_LEN) + logged_chars++; +} + +/* + * This is printk. It can be called from any context. We want it to work. + * + * We try to grab the console_sem. If we succeed, it's easy - we log the output and + * call the console drivers. If we fail to get the semaphore we place the output + * into the log buffer and return. The current holder of the console_sem will + * notice the new output in release_console_sem() and will send it to the + * consoles before releasing the semaphore. + * + * One effect of this deferred printing is that code which calls printk() and + * then changes console_loglevel may break. This is because console_loglevel + * is inspected when the actual printing occurs. + */ +asmlinkage int printk(const char *fmt, ...) +{ + va_list args; + unsigned long flags; + int printed_len; + char *p; + static char printk_buf[1024]; + static int log_level_unknown = 1; + + if (oops_in_progress) { + /* If a crash is occurring, make sure we can't deadlock */ + spin_lock_init(&logbuf_lock); + /* And make sure that we print immediately */ + init_MUTEX(&console_sem); + } + + /* This stops the holder of console_sem just where we want him */ + spin_lock_irqsave(&logbuf_lock, flags); + + /* Emit the output into the temporary buffer */ + va_start(args, fmt); + printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args); + va_end(args); + +#if 0 +// Useful Hack if things are going wrong very early in the day +(void)HYPERVISOR_console_write(printk_buf, sizeof(printk_buf)); +#endif + /* + * Copy the output into log_buf. If the caller didn't provide + * appropriate log level tags, we insert them here + */ + for (p = printk_buf; *p; p++) { + if (log_level_unknown) { + if (p[0] != '<' || p[1] < '0' || p[1] > '7' || p[2] != '>') { + emit_log_char('<'); + emit_log_char(default_message_loglevel + '0'); + emit_log_char('>'); + } + log_level_unknown = 0; + } + emit_log_char(*p); + if (*p == '\n') + log_level_unknown = 1; + } + + if (!arch_consoles_callable()) { + /* + * On some architectures, the consoles are not usable + * on secondary CPUs early in the boot process. + */ + spin_unlock_irqrestore(&logbuf_lock, flags); + goto out; + } + if (!down_trylock(&console_sem)) { + /* + * We own the drivers. We can drop the spinlock and let + * release_console_sem() print the text + */ + spin_unlock_irqrestore(&logbuf_lock, flags); + console_may_schedule = 0; + release_console_sem(); + } else { + /* + * Someone else owns the drivers. We drop the spinlock, which + * allows the semaphore holder to proceed and to call the + * console drivers with the output which we just produced. + */ + spin_unlock_irqrestore(&logbuf_lock, flags); + } +out: + return printed_len; +} +EXPORT_SYMBOL(printk); + +/** + * acquire_console_sem - lock the console system for exclusive use. + * + * Acquires a semaphore which guarantees that the caller has + * exclusive access to the console system and the console_drivers list. + * + * Can sleep, returns nothing. + */ +void acquire_console_sem(void) +{ + if (in_interrupt()) + BUG(); + down(&console_sem); + console_may_schedule = 1; +} +EXPORT_SYMBOL(acquire_console_sem); + +/** + * release_console_sem - unlock the console system + * + * Releases the semaphore which the caller holds on the console system + * and the console driver list. + * + * While the semaphore was held, console output may have been buffered + * by printk(). If this is the case, release_console_sem() emits + * the output prior to releasing the semaphore. + * + * If there is output waiting for klogd, we wake it up. + * + * release_console_sem() may be called from any context. + */ +void release_console_sem(void) +{ + unsigned long flags; + unsigned long _con_start, _log_end; + unsigned long must_wake_klogd = 0; + + for ( ; ; ) { + spin_lock_irqsave(&logbuf_lock, flags); + must_wake_klogd |= log_start - log_end; + if (con_start == log_end) + break; /* Nothing to print */ + _con_start = con_start; + _log_end = log_end; + con_start = log_end; /* Flush */ + spin_unlock_irqrestore(&logbuf_lock, flags); + call_console_drivers(_con_start, _log_end); + } + console_may_schedule = 0; + up(&console_sem); + spin_unlock_irqrestore(&logbuf_lock, flags); + if (must_wake_klogd && !oops_in_progress) + wake_up_interruptible(&log_wait); +} + +/** console_conditional_schedule - yield the CPU if required + * + * If the console code is currently allowed to sleep, and + * if this CPU should yield the CPU to another task, do + * so here. + * + * Must be called within acquire_console_sem(). + */ +void console_conditional_schedule(void) +{ + if (console_may_schedule && current->need_resched) { + set_current_state(TASK_RUNNING); + schedule(); + } +} + +void console_print(const char *s) +{ + printk(KERN_EMERG "%s", s); +} +EXPORT_SYMBOL(console_print); + +void console_unblank(void) +{ + struct console *c; + + acquire_console_sem(); + for (c = console_drivers; c != NULL; c = c->next) + if ((c->flags & CON_ENABLED) && c->unblank) + c->unblank(); + release_console_sem(); +} +EXPORT_SYMBOL(console_unblank); + +/* + * The console driver calls this routine during kernel initialization + * to register the console printing procedure with printk() and to + * print any messages that were printed by the kernel before the + * console driver was initialized. + */ +void register_console(struct console * console) +{ + int i; + unsigned long flags; + + /* + * See if we want to use this console driver. If we + * didn't select a console we take the first one + * that registers here. + */ + if (preferred_console < 0) { + if (console->index < 0) + console->index = 0; + if (console->setup == NULL || + console->setup(console, NULL) == 0) { + console->flags |= CON_ENABLED | CON_CONSDEV; + preferred_console = 0; + } + } + + /* + * See if this console matches one we selected on + * the command line. + */ + for(i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++) { + if (strcmp(console_cmdline[i].name, console->name) != 0) + continue; + if (console->index >= 0 && + console->index != console_cmdline[i].index) + continue; + if (console->index < 0) + console->index = console_cmdline[i].index; + if (console->setup && + console->setup(console, console_cmdline[i].options) != 0) + break; + console->flags |= CON_ENABLED; + console->index = console_cmdline[i].index; + if (i == preferred_console) + console->flags |= CON_CONSDEV; + break; + } + + if (!(console->flags & CON_ENABLED)) + return; + + /* + * Put this console in the list - keep the + * preferred driver at the head of the list. + */ + acquire_console_sem(); + if ((console->flags & CON_CONSDEV) || console_drivers == NULL) { + console->next = console_drivers; + console_drivers = console; + } else { + console->next = console_drivers->next; + console_drivers->next = console; + } + if (console->flags & CON_PRINTBUFFER) { + /* + * release_console_sem() will print out the buffered messages for us. + */ + spin_lock_irqsave(&logbuf_lock, flags); + con_start = log_start; + spin_unlock_irqrestore(&logbuf_lock, flags); + } + release_console_sem(); +} +EXPORT_SYMBOL(register_console); + +int unregister_console(struct console * console) +{ + struct console *a,*b; + int res = 1; + + acquire_console_sem(); + if (console_drivers == console) { + console_drivers=console->next; + res = 0; + } else { + for (a=console_drivers->next, b=console_drivers ; + a; b=a, a=b->next) { + if (a == console) { + b->next = a->next; + res = 0; + break; + } + } + } + + /* If last console is removed, we re-enable picking the first + * one that gets registered. Without that, pmac early boot console + * would prevent fbcon from taking over. + */ + if (console_drivers == NULL) + preferred_console = -1; + + + release_console_sem(); + return res; +} +EXPORT_SYMBOL(unregister_console); + +/** + * tty_write_message - write a message to a certain tty, not just the console. + * + * This is used for messages that need to be redirected to a specific tty. + * We don't put it into the syslog queue right now maybe in the future if + * really needed. + */ +void tty_write_message(struct tty_struct *tty, char *msg) +{ + if (tty && tty->driver.write) + tty->driver.write(tty, 0, msg, strlen(msg)); + return; +} diff --git a/xenolinux-2.4.21-sparse/mkbuildtree b/xenolinux-2.4.21-sparse/mkbuildtree index 8c02e17f1e..7fee0e70a3 100755 --- a/xenolinux-2.4.21-sparse/mkbuildtree +++ b/xenolinux-2.4.21-sparse/mkbuildtree @@ -169,7 +169,6 @@ ln -sf ../asm-i386/ucontext.h ln -sf ../asm-i386/unaligned.h ln -sf ../asm-i386/unistd.h ln -sf ../asm-i386/user.h -ln -sf ../asm-i386/vga.h ln -sf ../asm-i386/xor.h cd ../../arch/xeno/kernel -- 2.30.2